/*
 * 描述： <描述>
 * 修改人： rain
 * 修改时间： 2016年9月12日
 * 项目： p2p-taikongma
 */
package com.rainhy.webcore.token.mock;

import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import com.rainhy.webcore.token.context.Token;
import com.rainhy.webcore.token.context.TokenContext;
import com.rainhy.webcore.util.UUIDUtils;

/**
 * Token
 * 
 * @author rain
 * @version [版本号, 2016年9月12日]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
public class MockToken implements Token {
    
    /** context */
    private TokenContext tokenContext;
    
    /** tokenid */
    private String id;
    
    /** 创建时间 */
    private final long creationTime;
    
    /** 失效间隔,单位:毫秒 */
    private long maxInactiveInterval;
    
    /** 最后授权时间 */
    private long lastAccessedTime = System.currentTimeMillis();
    
    /** 参数 */
    private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
    
    /** 是否失效 */
    private boolean invalid = false;
    
    /** 是否新建 */
    private boolean isNew = true;
    
    public MockToken(HttpServletRequest request, HttpServletResponse response) {
        this.tokenContext = new MockTokenContext(request, response);
        this.id = StringUtils.upperCase(UUIDUtils.generateUUID());
        this.creationTime = System.currentTimeMillis();
    }
    
    public MockToken(Token token, HttpServletRequest request, HttpServletResponse response) {
        this.tokenContext = new MockTokenContext(request, response);
        if (token != null) {
            this.id = token.getId();
            this.creationTime = token.getCreationTime();
            this.maxInactiveInterval = token.getMaxInactiveInterval();
            this.lastAccessedTime = token.getLastAccessedTime();
            Enumeration<String> attributeNames = token.getAttributeNames();
            while (attributeNames.hasMoreElements()) {
                String attributeName = attributeNames.nextElement();
                this.attributes.put(attributeName, token.getAttribute(attributeName));
            }
            this.invalid = token.getLastAccessedTime() + token.getMaxInactiveInterval() < new Date().getTime();
            this.isNew = token.isNew();
        } else {
            this.id = StringUtils.upperCase(UUIDUtils.generateUUID());
            this.creationTime = System.currentTimeMillis();
        }
    }
    
    /** 重新授权 */
    public void access() {
        this.isNew = false;
        this.invalid = false;
        this.lastAccessedTime = System.currentTimeMillis();
    }
    
    /** 修改自身 id */
    public String changeTokenId() {
        this.id = StringUtils.upperCase(UUIDUtils.generateUUID());
        return this.id;
    }
    
    /** 清空 token 参数 */
    public void clearAttributes() {
        this.attributes.clear();
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        MockToken other = (MockToken) obj;
        if (id == null) {
            if (other.id != null)
                return false;
        } else if (!id.equals(other.id))
            return false;
        return true;
    }
    
    @Override
    public Object getAttribute(String name) {
        assertIsValid();
        Assert.notNull(name, "参数名不能为空");
        return this.attributes.get(name);
    }
    
    @Override
    public Enumeration<String> getAttributeNames() {
        assertIsValid();
        return Collections.enumeration(new LinkedHashSet<String>(this.attributes.keySet()));
    }
    
    @Override
    public long getCreationTime() {
        assertIsValid();
        return this.creationTime;
    }
    
    @Override
    public String getId() {
        return this.id;
    }
    
    @Override
    public long getLastAccessedTime() {
        assertIsValid();
        return this.lastAccessedTime;
    }
    
    @Override
    public long getMaxInactiveInterval() {
        return this.maxInactiveInterval;
    }
    
    /** context */
    @Override
    public TokenContext getTokenContext() {
        return tokenContext;
    }
    
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((id == null) ? 0 : id.hashCode());
        return result;
    }
    
    @Override
    public void invalidate() {
        assertIsValid();
        this.invalid = true;
        clearAttributes();
    }
    
    /** 是否已经失效 */
    public boolean isInvalid() {
        return this.invalid;
    }
    
    @Override
    public boolean isNew() {
        assertIsValid();
        return this.isNew;
    }
    
    @Override
    public void removeAttribute(String name) {
        assertIsValid();
        Assert.notNull(name, "参数名不能为空");
        this.attributes.remove(name);
    }
    
    @Override
    public void setAttribute(String name, Object value) {
        assertIsValid();
        Assert.notNull(name, "参数名不能为空");
        this.attributes.put(name, value);
    }
    
    /** 是否失效 */
    public void setInvalid(boolean invalid) {
        this.invalid = invalid;
    }
    
    /** 最后授权时间 */
    public void setLastAccessedTime(long lastAccessedTime) {
        this.lastAccessedTime = lastAccessedTime;
    }
    
    @Override
    public void setMaxInactiveInterval(long interval) {
        this.maxInactiveInterval = interval;
    }
    
    /** 新建 token */
    public void setNew(boolean value) {
        this.isNew = value;
    }
    
    /** context */
    public void setTokenContext(TokenContext tokenContext) {
        this.tokenContext = tokenContext;
    }
    
    /** 断言此 Token 是否已经失效 */
    private void assertIsValid() {
        if (isInvalid()) {
            throw new IllegalStateException("此 Token 已经失效");
        }
    }
}
